/*
 *  RenderingEngine.ES1.cpp
 *  NeHe.ES.Lesson08(http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=08)
 *
 *  Created by BongjuKim on 11. 1. 30..
 *  Copyright 2011 thinkware. All rights reserved.
 *
 */


#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>
#include "Interfaces.hpp"
#include "Matrix.hpp"
#include <cmath>
#include <iostream>
#include <assert.h>


namespace ES1 
{
	#define DEGREES_TO_RADIANS(__ANGLE__) ((__ANGLE__) / 180.0 * M_PI)
	
	// For glesut
	static void __gluMakeIdentityf(GLfloat m[16])
	{
		m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
		m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
		m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
		m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
	}
	
#define GLAPI GL_API
#define APIENTRY
	
#define __glPi 3.14159265358979323846
	
	GLAPI void APIENTRY
	gluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar)
	{
		GLfloat m[4][4];
		GLfloat sine, cotangent, deltaZ;
		GLfloat radians=(GLfloat)(fovy/2.0f*__glPi/180.0f);
		
		deltaZ=zFar-zNear;
		sine=(GLfloat)sin(radians);
		if ((deltaZ==0.0f) || (sine==0.0f) || (aspect==0.0f))
		{
			return;
		}
		cotangent=(GLfloat)(cos(radians)/sine);
		
		__gluMakeIdentityf(&m[0][0]);
		m[0][0] = cotangent / aspect;
		m[1][1] = cotangent;
		m[2][2] = -(zFar + zNear) / deltaZ;
		m[2][3] = -1.0f;
		m[3][2] = -2.0f * zNear * zFar / deltaZ;
		m[3][3] = 0;
		glMultMatrixf(&m[0][0]);
		
	}
	//
	
	
	class RenderingEngine : public IRenderingEngine 
	{
	public:
		RenderingEngine(IResourceManager* resourceManager);
		~RenderingEngine();
		void Initialize(int width, int height);
		void Render();
		void Render(const Visual* visual) const;
		void SetBmpTexture(const string& name);
		void SetTextData(const string& name);
		
		// For touch
		void UpdateAnimation(float timeStep) {}
		void OnRotate(DeviceOrientation newOrientation) {}
		void OnFingerUp(ivec2 location);
		void OnFingerDown(ivec2 location);
		void OnFingerMoved(ivec2 oldLocation, ivec2 newLocation);
		// For touch
		
		// For Sensor
		//void SetAccel(float ax, float ay, float az);
		// For Sensor
		
		
	private:
		GLboolean resizeWindow(int width, int height);
		GLboolean loadGLTextures();
		void destroyFramebuffer();

		// For Bitmap Context
		IResourceManager* m_resourceManager;

		GLuint m_framebuffer;
		GLuint m_colorRenderbuffer;
		GLuint m_depthRenderbuffer;
		
		bool light;
		bool blend;
		
		GLfloat xrot; /* X Rotation */
		GLfloat yrot; /* Y Rotation */
		GLfloat xspeed;
		GLfloat yspeed;
		GLfloat z;
		
		/* 주변광 : Ambient Light Values (NEW) */
		GLfloat LightAmbient[4];// = {0.1f, 0.1f, 0.1f, 1.0f};
		/* 분산광 : Diffuse Light Values (NEW) */
		GLfloat LightDiffuse[4];// = {1.0f, 1.0f, 1.0f, 1.0f};
		/* 광원 위치 : Light Position (NEW) */
		GLfloat LightPosition[4];// = {0.0f, 0.0f, 2.0f, 1.0f};
		
		/* Default OpenGL ES material settings */
		GLfloat box_material_amb[4];// = {0.2f, 0.2f, 0.2f, 0.2f};
		GLfloat box_material_dif[4];// = {0.8f, 0.8f, 0.8f, 0.8f};
		
		GLuint filter;// = 0; /* Which Filter To Use */
		GLuint texture[3]; /* Storage For One Texture ( NEW ) */
		
		

		// ------------------------------------
		// Anti alised lines data : F15
		// ------------------------------------
		void loader(const string& filename);
		void free_loader();
		void motion(int x, int y);
		
		/* load data structure from file */
		enum {VERTS, END};
		
		enum {X, Y, Z};
		enum {OBJ_ANGLE, OBJ_SCALE, OBJ_NONE};
		
		int winWidth;
		int winHeight;
		GLboolean smooth;
		GLboolean dblbuf;
		GLfloat objangle[2];
		GLfloat scale;
		int active;
		int lastx;
		int lasty;
		
		int verts;
		int lines;
		
		GLfloat* plane_lines[1000];
		GLfloat  verts_count[1000];
		// ------------------------------------
		
		
		// For touch
		GLfloat m_rotationAngle;
		GLfloat m_scale;
		ivec2	m_pivotPoint;
		// For touch
		
		// For Sensor
		GLfloat accel[3];
		GLboolean m_bIsFingerDown;
		// For Sensor
		
	};
	
	
	IRenderingEngine* CreateRenderingEngine(IResourceManager* resourceManager)
	{
		return new RenderingEngine(resourceManager);
	}
	
	RenderingEngine::RenderingEngine(IResourceManager* resourceManager)
	{
		m_resourceManager = resourceManager;

		light = false;
		blend = true;
		
		xrot = 0;
		yrot = 0;
		
		xspeed = 50.0f;
		yspeed = 50.0f;
		z = -8.0f;
		
		/* 주변광 : Ambient Light Values (NEW) */
		LightAmbient[0] = 0.5f;
		LightAmbient[1] = 0.5f;
		LightAmbient[2] = 0.5f;
		LightAmbient[3] = 1.0f;
		
		/* 분산광 : Diffuse Light Values (NEW) */
		LightDiffuse[0] = 1.0f;
		LightDiffuse[1] = 1.0f;
		LightDiffuse[2] = 1.0f;
		LightDiffuse[3] = 1.0f;
		
		/* 광원 위치 : Light Position (NEW) */
		LightPosition[0] = 0.0f;
		LightPosition[1] = 0.0f;
		LightPosition[2] = 2.0f;
		LightPosition[3] = 1.0f;
		
		/* Default OpenGL ES material settings */
		box_material_amb[0] = 0.2f;
		box_material_amb[1] = 0.2f;
		box_material_amb[2] = 0.2f;
		box_material_amb[3] = 0.2f;
		
		box_material_dif[0] = 0.8f;
		box_material_dif[1] = 0.8f;
		box_material_dif[2] = 0.8f;
		box_material_dif[3] = 0.8f;
		
		filter = 0; /* Which Filter To Use */
		
		glGenRenderbuffersOES(1, &m_colorRenderbuffer);
		glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
		
		
		// For anti-aliased lines
		winWidth = 320;
		winHeight = 480;
		smooth = GL_FALSE;
		dblbuf = GL_TRUE;
		objangle[0] = 0.0f;
		objangle[1] = 0.0f;
		scale = 1.0f;
		active = OBJ_NONE;
		lastx = 0;
		lasty = 0;
		
		verts = 0;
		lines = 0;
		
		// For Sensor
		m_bIsFingerDown = false;
		// For Sensor
		
//		for (int i=0; i<1000; i++) {
//			memset(&plane_lines[i], 0, sizeof(GLfloat));
//			memset(&verts_count[i], 0, sizeof(GLfloat));
//		}

	}
	
	RenderingEngine::~RenderingEngine()
	{
		destroyFramebuffer();
		
		free_loader();
	}
	
	void RenderingEngine::destroyFramebuffer()
	{
		glDeleteFramebuffersOES(1, &m_framebuffer);
		m_framebuffer = 0;
		glDeleteRenderbuffersOES(1, &m_colorRenderbuffer);
		m_colorRenderbuffer = 0;
		
		if (m_depthRenderbuffer) {
			glDeleteRenderbuffersOES(1, &m_depthRenderbuffer);
			m_depthRenderbuffer = 0;
		}
	}

	GLboolean RenderingEngine::loadGLTextures()
	{
		GLboolean Status = false;
		
//		// Load To Bitmap, Check For Errors, If Bitmap's Not Found Quit
//		if (glbmp_LoadBitmap("/sdcard/nehe.bmp", 0, &bitmap))
//		{
//			std::cout << "SUCCEEDED OPEN FILE" << "\r\n";
//			//__android_log_print(ANDROID_LOG_ERROR, "NeHe.ES.lesson06", "SUCCEEDED OPEN FILE");
//			
//			/* Since OpenGL ES 1.0/1.1 has no BGRA extension we must swap R & B */
//			Status = true;
//			
//			/* Create The Texture */
//			glGenTextures(1, &texture[0]);
//			
//			/* Typical Texture Generation Using Data From The Bitmap */
//			glBindTexture(GL_TEXTURE_2D, texture[0]);
//			
//			//copy data from bitmap into texture
//			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmap.width, bitmap.height,
//						 0, GL_RGB, GL_UNSIGNED_BYTE, bitmap.rgb_data);
//			
//			//set up texture filtering
//			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//			
//			//free the bitmap
//			glbmp_FreeBitmap(&bitmap);
//		} else {
//			//__android_log_print(ANDROID_LOG_ERROR, "NeHe.ES.lesson06", "FAILED OPEN FILE");
//			std::cout << "FAILED OPEN FILE" << "\r\n";
//		}
		
		return Status;
	}
			
	
	//
	// initGL()
	void RenderingEngine::Initialize(int width, int height)
	{
		m_pivotPoint = ivec2(width / 2, height / 2);
		
		// Create the depth buffer.
		glGenRenderbuffersOES(1, &m_depthRenderbuffer);
		glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_depthRenderbuffer);
		glRenderbufferStorageOES(GL_RENDERBUFFER_OES,
								 GL_DEPTH_COMPONENT16_OES,
								 width,
								 height);
		
		// Create the framebuffer object; attach the depth and color buffers.
		glGenFramebuffersOES(1, &m_framebuffer);
		glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_framebuffer);
		glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
									 GL_COLOR_ATTACHMENT0_OES,
									 GL_RENDERBUFFER_OES,
									 m_colorRenderbuffer);
		glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
									 GL_DEPTH_ATTACHMENT_OES,
									 GL_RENDERBUFFER_OES,
									 m_depthRenderbuffer);
		
		// Bind the color buffer for rendering.
		glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
		
		
		// Get width and height info.
		glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &width);
		glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &height);
//		std::cout << "Initialize " << width << ":" << height << "\r\n";
		//
		
		/* initialize OpenGL */
		glMatrixMode(GL_PROJECTION);
//		glOrthof(-1., 1., -1., 1., -5., 5.);
		glLoadIdentity();
		gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f);
		
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
		
//		loader("f15.data");
		
		/* Resize Window */
		resizeWindow(width, height);
	}

	GLboolean RenderingEngine::resizeWindow(int width, int height)
	{
		winWidth = width;
		winHeight = height;
		
		glViewport(0, 0, winWidth, winHeight);
		
		return true;
	}
	
	void RenderingEngine::Render(const Visual* visual) const
	{
		int it;
		mat4 m_translation = mat4::Translate(0, 0, -3);
		
//		printf("TEST0001\n");
//		std::cout << "TEST01:" << 100.0 << "TEST02:" << 200.0 << std::endl;
//		std::cout << "TEST03:" << 300.0 << "TEST04:" << 400.0 << "\n";
		
		glClear(GL_COLOR_BUFFER_BIT);
		
		// Set the viewport transform.
		ivec2 size = visual->ViewportSize;
		ivec2 lowerLeft = visual->LowerLeft;
		glViewport(lowerLeft.x, lowerLeft.y, size.x, size.y);
		
		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		gluPerspective(45.0f, (GLfloat)size.x/(GLfloat)size.y, 0.1f, 1000.0f);
		
		// Set the model-view transform.
		mat4 rotation = visual->Orientation.ToMatrix();
		mat4 modelview = rotation * m_translation;
		glMatrixMode(GL_MODELVIEW);
		// 회전 변환
		glLoadMatrixf(modelview.Pointer());
		
//		// Z축은 90도 위로 올리도록 한다.
//		glRotatef(90.0f, 0.0f, 0.0f, 1.0f);

		// 척도 변환
		glScalef(1.2, 1.2, 1.2);
		
		// Set the color.
		vec3 color = visual->Color;
		glColor4f(color.x, color.y, color.z, 1);
		
		/* Draw arrays */
		for (it=0; it<lines; it++)
		{
			glVertexPointer(3, GL_FLOAT, 0, plane_lines[it]);
			glEnableClientState(GL_VERTEX_ARRAY);
			glDrawArrays(GL_LINE_STRIP, 0, verts_count[it]);
			glDisableClientState(GL_VERTEX_ARRAY);
		}
		
		glFlush();
		
	}
	
	// drawGLScene()
	void RenderingEngine::Render()
	{
		int it;
		
		int width=0, height=0;
		glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &width);
		glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &height);
		
		glClear(GL_COLOR_BUFFER_BIT);
		
		glPushMatrix();
		
		if (m_bIsFingerDown == false) {
			
			GLfloat matrix[4][4], length;
			
			// 단위 벡터 생성을 위한 length를 구한다.
			length = sqrtf(accel[0]*accel[0] + accel[1]*accel[1] + accel[2]*accel[2]);
			
			// Model view matrix를 설정한다.
			glMatrixMode(GL_PROJECTION);
			glLoadIdentity();
			gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f);
			glMatrixMode(GL_MODELVIEW);
			glLoadIdentity();
			
			glTranslatef(0.0f, 0.0f, -5.0f);
			glScalef(1.5, 1.5, 1.5);
			
			if (length >= 0.1) {
				// Gravity Vector 기반으로 회전 변환을 시키기 전에 행렬 집합을 초기화 한다.
				bzero(matrix, sizeof(matrix));
				matrix[3][3] = 1.0f;
				
				// 첫 번째 열 벡터를 설정한다.
				matrix[0][0] = accel[0] / length;
				matrix[0][1] = accel[1] / length;
				matrix[0][2] = accel[2] / length;
				
				// 두 번째 열 벡터를 설정한다.
				// Gravity 벡터의 Gx, Gy는 0과 1로 직교하도록 설정한다. Gz축은 tan(theta)값인 y/z값으로 회전하도록 설정한다.
				matrix[1][0] = 0.0f;
				matrix[1][1] = 1.0f;
				matrix[1][2] = -accel[1] / accel[2];
				length = sqrtf(matrix[1][0]*matrix[1][0] + matrix[1][1]*matrix[1][1] + matrix[1][2]*matrix[1][2]);
				matrix[1][0] /= length;
				matrix[1][1] /= length;
				matrix[1][2] /= length;
				
				// 세 번째 열 벡터를 설정한다.
				// 먼저 계산한 두 벡터의 외적 값을 설정한다.
				matrix[2][0] = matrix[0][1]*matrix[1][2] - matrix[0][2]*matrix[1][1];
				matrix[2][1] = matrix[1][0]*matrix[0][2] - matrix[1][2]*matrix[0][0];
				matrix[2][2] = matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0];
				
				// matrix를 opengl pipeline에 적재한다.
				glMultMatrixf((GLfloat*)matrix);
				
				// Z축은 90도 위로 올리도록 한다.
				glRotatef(90.0f, 0.0f, 0.0f, 1.0f);
	
			}
			
			
		} else {
			
			Quaternion dX = Quaternion::CreateFromAxisAngle(vec3(0.0f,1.0f,0.0f), DEGREES_TO_RADIANS(objangle[X]));
			Quaternion dY = Quaternion::CreateFromAxisAngle(vec3(1.0f,0.0f,0.0f), DEGREES_TO_RADIANS(objangle[Y]));
			
			Quaternion orientation = dX.Rotated(dY);
			
			mat4 rotation = orientation.ToMatrix();
			mat4 m_translation = mat4::Translate(0, 0, -7);
			mat4 modelview = rotation * m_translation;
			glMatrixMode(GL_MODELVIEW);
			glLoadMatrixf(rotation.Pointer());
			
			// Set the projection transform.
//			float h = 4.0f * height / width;
//			mat4 projection = mat4::Frustum(-2, 2, -h/2, h/2, 5, 10);
//			glMatrixMode(GL_PROJECTION);
//			glLoadMatrixf(projection.Pointer());
			
			glMatrixMode(GL_PROJECTION);
			glLoadIdentity();
			glOrthof(-1., 1., -1., 1., -5., 5.);
			
			
			
//			glMatrixMode(GL_PROJECTION);
//			glLoadIdentity();
//			glOrthof(-1., 1., -1., 1., -5., 5.);
//			glMatrixMode(GL_MODELVIEW);
//			glLoadIdentity();			
//			
//			glRotatef(objangle[X], 0.f, 1.f, 0.f); /* rotate object */
//			glRotatef(objangle[Y], 1.f, 0.f, 0.f);
//			glScalef(scale, scale, scale);
		}

		
		
		/* Draw arrays */
		for (it=0; it<lines; it++)
		{
			glVertexPointer(3, GL_FLOAT, 0, plane_lines[it]);
			glEnableClientState(GL_VERTEX_ARRAY);
			glDrawArrays(GL_LINE_STRIP, 0, verts_count[it]);
			glDisableClientState(GL_VERTEX_ARRAY);
		}
		
		glPopMatrix();

		glFlush();
	}
	
	
	// loadBMP
	// loadGLTextures()
	void RenderingEngine::SetBmpTexture(const string& filename)
	{
		TextureDescription description = m_resourceManager->LoadImage(filename);
		
		GLenum format;
		switch (description.Format) {
			case TextureFormatGray:
				format = GL_LUMINANCE;
				break;
				
			case TextureFormatGrayAlpha:
				format = GL_LUMINANCE_ALPHA;
				break;

			case TextureFormatRgb:
				format = GL_RGB;
				break;
				
			case TextureFormatRgba:
				format = GL_RGBA;
				break;
				
			default:
				break;
		}
		
		GLenum type;
		switch (description.BitsPerComponent) {
			case 8:
				type = GL_UNSIGNED_BYTE;
				break;

			case 4:
				if (format == GL_RGBA) {
					type = GL_UNSIGNED_SHORT_4_4_4_4;
					break;
				}
				// intentionally fall through
			default:
				assert("Unsupported format.");
				break;
		}
		
		void* data = m_resourceManager->GetImageData();
		ivec2 size = description.Size;
		
		
//		std::cout << "SUCCEEDED OPEN FILE" << "\r\n";
				
		
		/* Create The Texture */
		// texture[0] = Nearest Filtering
		// texture[1] = Linear Filtering
		// texture[2] = MIPMAP Filtering
        glGenTextures(3, &texture[0]);
		
        /* Load in texutre 1 */
        /* Typical Texture Generation Using Data From The Bitmap */
        glBindTexture(GL_TEXTURE_2D, texture[0]);
		
		/* Generate The Texture */
		glTexImage2D(GL_TEXTURE_2D, 0, format, size.x, size.y, 0, format, type, data);
//		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmap.width, bitmap.height,
//					 0, GL_RGB, GL_UNSIGNED_BYTE, bitmap.rgb_data);
		
		/* Nearest Filtering */
		glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		
		/* Load in texture 2 */
		/* Typical Texture Generation Using Data From The Bitmap */
		glBindTexture(GL_TEXTURE_2D, texture[1]);
		
		/* Linear Filtering */
		glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		
		/* Generate The Texture */
		glTexImage2D(GL_TEXTURE_2D, 0, format, size.x, size.y, 0, format, type, data);
//		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmap.width, bitmap.height,
//					 0, GL_RGB, GL_UNSIGNED_BYTE, bitmap.rgb_data);
		
		/* Load in texture 3 using mipmap */
		glBindTexture(GL_TEXTURE_2D, texture[2]);
		glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
		glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		// gluBuild2DMimaps 를 iPhone 에 맞게금 변경.
//		gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, bitmap.width, bitmap.height,
//						  GL_RGB, GL_UNSIGNED_BYTE, bitmap.rgb_data);
		glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
		glTexImage2D(GL_TEXTURE_2D, 0, format, size.x, size.y, 0, format, type, data);
		
		m_resourceManager->UnloadImage();
	}
	

	// load Text Data : f15.data
	void RenderingEngine::SetTextData(const string& filename)
	{
		FILE* fp;
		GLfloat x, y, z;
		int state = END;
		int read;
		
		//fp = fopen(filename.c_str(), "r");
		fp = m_resourceManager->LoadTextData(filename);
		
		if (!fp) {
			// exit(1);
//			std::cout << "can't open file : " << filename << "  \r\n";
			return;
		}
		
		//		NSString* path = [[NSBundle mainBundle] m_resourceManager->pathForResource: @"f15" ofType: @"data"];
		
		
		/*
		 Just to be clear to open a file "some.txt"...
		 
		 NSString * path = [[NSBundle mainBundle] pathForResource:  @"some" ofType: @"txt"];
		 FILE *f = fopen([path cStringUsingEncoding:1],"r");
		 if (f == NULL) NSLog([path stringByAppendingString:@" not found"]);
		 */
		
		while(!feof(fp))
		{
//			std::cout << "state:" << state << "  \r\n";
			
			switch(state)
			{
				case END:
					read = fscanf(fp, " v");
					if (read < 0) /* hit eof */
					{
						break;
					}
					state = VERTS;
					plane_lines[lines] =(GLfloat*)malloc(1024);
					break;
					
				case VERTS:
					read = fscanf(fp, " %f %f %f", &x, &y, &z);
					if (read == 3)
					{
						*(plane_lines[lines]+verts*3 + 0) = x;
						*(plane_lines[lines]+verts*3 + 1) = y;
						*(plane_lines[lines]+verts*3 + 2) = z;
						verts++;
					}
					else
					{
						fscanf(fp, " e");
						verts_count[lines]=verts;
						verts=0;
						lines++;
						state = END;
					}
					break;
			}
		}
		
		fclose(fp);
	}
	
	
	// load Text Data : f15.data
	void RenderingEngine::loader(const string& filename)
	{
		FILE* fp;
		GLfloat x, y, z;
		int state = END;
		int read;
		
		fp = fopen(filename.c_str(), "r");
		if (!fp) {
			// exit(1);
//			std::cout << "can't open file : " << filename << "  \r\n";
			return;
		}
		
//		NSString* path = [[NSBundle mainBundle] m_resourceManager->pathForResource: @"f15" ofType: @"data"];
		
		
		/*
		 Just to be clear to open a file "some.txt"...
		 
		 NSString * path = [[NSBundle mainBundle] pathForResource:  @"some" ofType: @"txt"];
		 FILE *f = fopen([path cStringUsingEncoding:1],"r");
		 if (f == NULL) NSLog([path stringByAppendingString:@" not found"]);
		 */
		
		while(!feof(fp))
		{
//			std::cout << "state:" << state << "  \r\n";

			switch(state)
			{
				case END:
					read = fscanf(fp, " v");
					if (read < 0) /* hit eof */
					{
						break;
					}
					state = VERTS;
					plane_lines[lines] =(GLfloat*)malloc(1024);
					break;
					
				case VERTS:
					read = fscanf(fp, " %f %f %f", &x, &y, &z);
					if (read == 3)
					{
						*(plane_lines[lines]+verts*3 + 0) = x;
						*(plane_lines[lines]+verts*3 + 1) = y;
						*(plane_lines[lines]+verts*3 + 2) = z;
						verts++;
					}
					else
					{
						fscanf(fp, " e");
						verts_count[lines]=verts;
						verts=0;
						lines++;
						state = END;
					}
					break;
			}
		}
		
		fclose(fp);
	}
	
	void RenderingEngine::free_loader()
	{
		int it;
		
		for (it = 0; it < lines; it++) {
			free(plane_lines[it]);
		}
	}
	
	void RenderingEngine::motion(int x, int y)
	{
		switch (active) {
			case OBJ_ANGLE:
				objangle[X] = (x - winWidth/2) * 360./winWidth;
				objangle[Y] = (y - winHeight/2) * 360./winHeight;
				
//				std::cout << "motion = objangle.x:" << objangle[X] << "  objangle.y:" << objangle[Y] << "\r\n";

				break;
				
			case OBJ_SCALE:
				scale = x * 5./winWidth;
				objangle[Y] = (y - winHeight/2) * 360./winHeight;
				break;

			default:
				break;
		}
		
		lastx = x;
		lasty = y;
	}
	
	
#pragma mark -
#pragma mark For User Interactive : OnRotate() and etcs.
	
	void RenderingEngine::OnFingerUp(ivec2 location)
	{
//		m_scale = 1.0f;
		
		m_bIsFingerDown = false;
	}
	
	void RenderingEngine::OnFingerDown(ivec2 location)
	{
//		m_scale = 1.5f;
//		OnFingerMoved(location, location);

		m_bIsFingerDown = true;
		
//		std::cout << "Down = location.x:" << location.x << "  location.y:" << location.y << "\r\n";

		active = OBJ_SCALE;
		motion(location.x, location.y);
		active = OBJ_NONE;
	}
	
	void RenderingEngine::OnFingerMoved(ivec2 previous, ivec2 location)
	{
//		std::cout << "Moved = location.x:" << location.x << "  location.y:" << location.y << "\r\n";
		
		m_bIsFingerDown = true;
		
		active = OBJ_ANGLE;
		motion(location.x, location.y);
		active = OBJ_NONE;
		
//		vec2 direction = vec2(location - m_pivotPoint).Normalized();
//		
//		// Flip the y-axis because pixel coords increase toward the bottom.
//		direction.y = -direction.y;
//		
//		m_rotationAngle = std::acos(direction.y) * 180.0f / 3.14159f;
//		if (direction.x > 0) {
//			m_rotationAngle = -m_rotationAngle;
//		}
	}
	
//	// For Sensor
//	void RenderingEngine::SetAccel(float ax, float ay, float az)
//	{
//		accel[0] = ax;
//		accel[1] = ay;
//		accel[2] = az;
//		
//		char str[256];
//		
//		sprintf(str, "RenderingEngine : accelX(%f), accelY(%f), accelZ(%f) \r\n", accel[0], accel[1], accel[2]);
//		
//		std::cout << str;
//		
//	}
//	// For Sensor
	
} // namespace ES1 













